package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayListReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayTimeRangeReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayTimeRangeResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.weekdayscheme.WeekdaySchemeTimeRangeItemResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.weekdayscheme.WeekdaySchemeTimeRangeResVo;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.ProjectConstants;
import com.zmj.sy.mom.srv.aps.utils.SyExceptionUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RequiredArgsConstructor
@Service
public class StationWeekdayService {

    private final StationWeekdayMapper stationWeekdayMapper;

    private final StationWeekdaySchemeMapper stationWeekdaySchemeMapper;

    private final StationWeekdayRuleMapper stationWeekdayRuleMapper;

    private final ShiftMapper shiftMapper;
    private final StationMapper stationMapper;
    private final ShiftTypeMapper shiftTypeMapper;
    private final WeekdayRuleMapper weekdayRuleMapper;

    @SuppressWarnings("unchecked")
    public BaseListResVo<StationWeekdayListResVo> list(StationWeekdayListReqVo reqVo) {
        LambdaQueryWrapper<StationWeekday> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StationWeekday::getStationId, reqVo.getStationId());
        wrapper.between(StationWeekday::getShiftDay, reqVo.getStartDate(), reqVo.getEndDate());
        wrapper.orderByAsc(StationWeekday::getShiftDay, StationWeekday::getShiftSeq);
        List<StationWeekday> weekdays = stationWeekdayMapper.selectList(wrapper);

        return BaseListResVo.of(weekdays, StationWeekdayListResVo.class);
    }

    public BaseListResVo<StationWeekdayTimeRangeResVo> timeRange(StationWeekdayTimeRangeReqVo reqVo) {


        StationWeekdayScheme scheme = stationWeekdaySchemeMapper.selectById(reqVo.getId());


        LocalDate startDate = scheme.getStartDate();
        LocalDate endDate = scheme.getEndDate();
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().eq(Shift::getShiftTypeId, scheme.getShiftTypeId()));
        if(shifts.isEmpty()){
            throw SyExceptionUtils.e("该方案没有班制，请先配置班制");
        }
        List<StationWeekdayRule> ruleList = stationWeekdayRuleMapper.selectList(Wrappers.<StationWeekdayRule>lambdaQuery().eq(StationWeekdayRule::getStationId, scheme.getStationId()));

        List<WeekdaySchemeTimeRangeResVo> allWeekday = Stream
                .iterate(startDate, s -> s.plusDays(1))
                .limit(startDate.until(endDate, ChronoUnit.DAYS) + 1)
                .map(e -> {
                    WeekdaySchemeTimeRangeResVo newDay = new WeekdaySchemeTimeRangeResVo();
                    newDay.setShiftDay(e);

                    for (Shift shift : shifts) {
                        WeekdaySchemeTimeRangeItemResVo item  = new WeekdaySchemeTimeRangeItemResVo();
                        item.setShiftSeq(shift.getSeq());
                        item.setOffsetStartDay(shift.getOffsetStartDay());
                        item.setOffsetEndDay(shift.getOffsetEndDay());
                        item.setStartTime(shift.getStartTime());
                        item.setEndTime(shift.getEndTime());
                        item.setShiftId(shift.getId());
                        newDay.getItem().add(item);
                    }
                    return newDay;
                })
                .collect(Collectors.toList());

        // 匹配规则，可以抽成策略模式，数据量大，为了效率不建议
        for (WeekdaySchemeTimeRangeResVo w : allWeekday) {
            for (StationWeekdayRule weekdayRule : ruleList) {
                if (weekdayRule.getType() == 4) {
                    if (weekdayRule.getValue().equals(String.valueOf(w.getShiftDay().getDayOfWeek().getValue()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                    }
                } else if (weekdayRule.getType() == 1){
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    LocalDate start = LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER);
                    LocalDate end = LocalDate.parse(split[1], DatePattern.NORM_DATE_FORMATTER);
                    if (w.getShiftDay().compareTo(start) >= 0 && w.getShiftDay().compareTo(end) <= 0) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        for (WeekdaySchemeTimeRangeItemResVo weekdaySchemeTimeRangeItemResVo : w.getItem()) {
                            weekdaySchemeTimeRangeItemResVo.setWorkState(w.getWorkState());
                            weekdaySchemeTimeRangeItemResVo.setText(weekdayRule.getText());
                        }
                    }

                } else if (weekdayRule.getType() == 3) {
                    if (LocalDate.parse(weekdayRule.getValue(), DatePattern.NORM_DATE_FORMATTER).equals(w.getShiftDay())) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        for (WeekdaySchemeTimeRangeItemResVo item : w.getItem()) {
                            item.setWorkState(w.getWorkState());
                        }
                    }
                } else if (weekdayRule.getType() == 2) {
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    if(split.length != 2){
                        throw SyExceptionUtils.e("日期规则配置错误{}", value);
                    }
                    if(w.getShiftDay().equals(LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER))){
                            w.getItem().stream().filter(e -> e.getShiftId().equals(Integer.valueOf(split[1]))).findFirst().ifPresent(e -> {
                                e.setWorkState(weekdayRule.getStatus());
                                e.setText(weekdayRule.getText());
                            });
                    }



                }
            }
        }

        Map<LocalDate, WeekdaySchemeTimeRangeResVo> collect = allWeekday.stream().collect(Collectors.toMap(WeekdaySchemeTimeRangeResVo::getShiftDay, e -> e));
        List<WeekdaySchemeTimeRangeResVo> resVoList = Stream.iterate(reqVo.getStart(), e -> e.plusDays(1L))
                .limit(reqVo.getStart().until(reqVo.getEnd(), ChronoUnit.DAYS) + 1)
                .filter(collect::containsKey)
                .map(e -> {

                    WeekdaySchemeTimeRangeResVo r = new WeekdaySchemeTimeRangeResVo();
                    r.setShiftDay(e);
                    WeekdaySchemeTimeRangeResVo weekdaySchemeTimeRangeResVo = collect.get(e);
                    r.setWorkState(weekdaySchemeTimeRangeResVo.getWorkState());
                    r.setText(weekdaySchemeTimeRangeResVo.getText());
                    r.setDateType(weekdaySchemeTimeRangeResVo.getDateType());


                    List<WeekdaySchemeTimeRangeItemResVo> weekdays1 = collect.get(e).getItem();
                    for (WeekdaySchemeTimeRangeItemResVo item : weekdays1) {
                        if(item.getWorkState() == null){
                            item.setWorkState(r.getWorkState());
                        }
                    }

                    if (weekdays1.isEmpty()) {
                        r.setText("无");
                        r.setItem(new ArrayList<>());
                    } else {
                        r.setText(weekdays1.get(0).getText());
                        List<WeekdaySchemeTimeRangeItemResVo> collect1 = weekdays1.stream().filter(e1 -> !ObjectUtils.isEmpty(e1.getWorkState())&& !e1.getWorkState().equals(r.getWorkState())).collect(Collectors.toList());
                        r.setItem(collect1);
                    }

                    return r;
                })
                .collect(Collectors.toList());


        return BaseListResVo.of(resVoList, StationWeekdayTimeRangeResVo.class);

    }

    public BaseListResVo<StationWeekdayTimeRangeResVo> stationTimeRange(StationWeekdayTimeRangeReqVo reqVo) {


//        StationWeekdayScheme scheme = stationWeekdaySchemeMapper.selectById(reqVo.getId());

        Station station = stationMapper.selectById(reqVo.getId());

        ShiftType shiftType = shiftTypeMapper.selectById(station.getShiftTypeId());

        LocalDate startDate = shiftType.getStartDate();
        LocalDate endDate = shiftType.getEndDate();
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().eq(Shift::getShiftTypeId, shiftType.getId()));
        if(shifts.isEmpty()){
            throw SyExceptionUtils.e("该方案没有班制，请先配置班制");
        }
        List<WeekdayRule> ruleList = weekdayRuleMapper.selectList(Wrappers.<WeekdayRule>lambdaQuery().eq(WeekdayRule::getShiftTypeId, shiftType.getId()));

        List<WeekdaySchemeTimeRangeResVo> allWeekday = Stream
                .iterate(startDate, s -> s.plusDays(1))
                .limit(startDate.until(endDate, ChronoUnit.DAYS) + 1)
                .map(e -> {
                    WeekdaySchemeTimeRangeResVo newDay = new WeekdaySchemeTimeRangeResVo();
                    newDay.setShiftDay(e);

                    for (Shift shift : shifts) {
                        WeekdaySchemeTimeRangeItemResVo item  = new WeekdaySchemeTimeRangeItemResVo();
                        item.setShiftSeq(shift.getSeq());
                        item.setOffsetStartDay(shift.getOffsetStartDay());
                        item.setOffsetEndDay(shift.getOffsetEndDay());
                        item.setStartTime(shift.getStartTime());
                        item.setEndTime(shift.getEndTime());
                        item.setShiftId(shift.getId());
                        newDay.getItem().add(item);
                    }
                    return newDay;
                })
                .collect(Collectors.toList());

        // 匹配规则，可以抽成策略模式，数据量大，为了效率不建议
        for (WeekdaySchemeTimeRangeResVo w : allWeekday) {
            for (WeekdayRule weekdayRule : ruleList) {
                if (weekdayRule.getType() == 4) {
                    if (weekdayRule.getValue().equals(String.valueOf(w.getShiftDay().getDayOfWeek().getValue()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                    }
                } else if (weekdayRule.getType() == 1){
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    LocalDate start = LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER);
                    LocalDate end = LocalDate.parse(split[1], DatePattern.NORM_DATE_FORMATTER);
                    if (w.getShiftDay().compareTo(start) >= 0 && w.getShiftDay().compareTo(end) <= 0) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        for (WeekdaySchemeTimeRangeItemResVo weekdaySchemeTimeRangeItemResVo : w.getItem()) {
                            weekdaySchemeTimeRangeItemResVo.setWorkState(w.getWorkState());
                            weekdaySchemeTimeRangeItemResVo.setText(weekdayRule.getText());
                        }
                    }

                } else if (weekdayRule.getType() == 3) {
                    if (LocalDate.parse(weekdayRule.getValue(), DatePattern.NORM_DATE_FORMATTER).equals(w.getShiftDay())) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        for (WeekdaySchemeTimeRangeItemResVo item : w.getItem()) {
                            item.setWorkState(w.getWorkState());
                        }
                    }
                } else if (weekdayRule.getType() == 2) {
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    if(split.length != 2){
                        throw SyExceptionUtils.e("日期规则配置错误{}", value);
                    }
                    if(w.getShiftDay().equals(LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER))){
                        w.getItem().stream().filter(e -> e.getShiftId().equals(Integer.valueOf(split[1]))).findFirst().ifPresent(e -> {
                            e.setWorkState(weekdayRule.getStatus());
                            e.setText(weekdayRule.getText());
                        });
                    }



                }
            }
        }

        Map<LocalDate, WeekdaySchemeTimeRangeResVo> collect = allWeekday.stream().collect(Collectors.toMap(WeekdaySchemeTimeRangeResVo::getShiftDay, e -> e));
        List<WeekdaySchemeTimeRangeResVo> resVoList = Stream.iterate(reqVo.getStart(), e -> e.plusDays(1L))
                .limit(reqVo.getStart().until(reqVo.getEnd(), ChronoUnit.DAYS) + 1)
                .filter(collect::containsKey)
                .map(e -> {

                    WeekdaySchemeTimeRangeResVo r = new WeekdaySchemeTimeRangeResVo();
                    r.setShiftDay(e);
                    WeekdaySchemeTimeRangeResVo weekdaySchemeTimeRangeResVo = collect.get(e);
                    r.setWorkState(weekdaySchemeTimeRangeResVo.getWorkState());
                    r.setText(weekdaySchemeTimeRangeResVo.getText());
                    r.setDateType(weekdaySchemeTimeRangeResVo.getDateType());


                    List<WeekdaySchemeTimeRangeItemResVo> weekdays1 = collect.get(e).getItem();
                    for (WeekdaySchemeTimeRangeItemResVo item : weekdays1) {
                        if(item.getWorkState() == null){
                            item.setWorkState(r.getWorkState());
                        }
                    }

                    if (weekdays1.isEmpty()) {
                        r.setText("无");
                        r.setItem(new ArrayList<>());
                    } else {
                        r.setText(weekdays1.get(0).getText());
                        List<WeekdaySchemeTimeRangeItemResVo> collect1 = weekdays1.stream().filter(e1 -> !ObjectUtils.isEmpty(e1.getWorkState())&& !e1.getWorkState().equals(r.getWorkState())).collect(Collectors.toList());
                        r.setItem(collect1);
                    }

                    return r;
                })
                .collect(Collectors.toList());


        return BaseListResVo.of(resVoList, StationWeekdayTimeRangeResVo.class);

    }

   /* public List<Weekday> getWeekdays(StationWeekdayScheme scheme) {
        LocalDate startDate = scheme.getStartDate();
        LocalDate endDate = scheme.getEndDate();
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().eq(Shift::getShiftTypeId, scheme.getShiftTypeId()));
        List<StationWeekdayRule> ruleList = stationWeekdayRuleMapper.selectList(Wrappers.<StationWeekdayRule>lambdaQuery().eq(StationWeekdayRule::getStationWeekdaySchemeId, scheme.getId()));

        List<Weekday> allWeekday = Stream
                .iterate(startDate, s -> s.plusDays(1))
                .limit(startDate.until(endDate, ChronoUnit.DAYS) + 1)
                .flatMap(e ->
                        shifts.stream()
                                .map(shift -> {
                                    Weekday newDay = new Weekday();
                                    MkBeanUtils.copyPropertiesIgnore(shift, newDay);
                                    newDay.setShiftDay(e);
                                    newDay.setShiftSeq(shift.getSeq());
                                    newDay.setShiftId(shift.getId());
                                    return newDay;
                                })
                )
                .collect(Collectors.toList());

        // 匹配规则，可以抽成策略模式，数据量大，为了效率不建议
        for (Weekday w : allWeekday) {
            for (StationWeekdayRule weekdayRule : ruleList) {
                if (weekdayRule.getType() == 4) {
                    if (weekdayRule.getValue().equals(String.valueOf(w.getShiftDay().getDayOfWeek().getValue()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setWeekdayRuleId(weekdayRule.getId());
                    }
                } else if (weekdayRule.getType() == 1){
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    LocalDate start = LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER);
                    LocalDate end = LocalDate.parse(split[1], DatePattern.NORM_DATE_FORMATTER);
                    if (w.getShiftDay().compareTo(start) >= 0 && w.getShiftDay().compareTo(end) <= 0) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        w.setWeekdayRuleId(weekdayRule.getId());
                    }

                } else if (weekdayRule.getType() == 3) {
                    if (LocalDate.parse(weekdayRule.getValue(), DatePattern.NORM_DATE_FORMATTER).equals(w.getShiftDay())) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        w.setWeekdayRuleId(weekdayRule.getId());
                    }
                } else if (weekdayRule.getType() == 2) {
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    if (split[0].equals(w.getShiftDay().toString()) && split[1].equals(String.valueOf(w.getShiftId()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        w.setWeekdayRuleId(weekdayRule.getId());
                    }
                }
            }
        }
        return allWeekday;
    }*/
}
